package mlpEnsemble;

import genetic_algorithm.Chromosome;
import genetic_algorithm.FitnessFunction;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Vector;

import utils.VectorClassificationPair;

public class MlpEnsembleFitness implements FitnessFunction {

	private static final String RESULTS_FILE = "mlp_ensemble_results.txt";
	
	static List<VectorClassificationPair > testData; // a test example (float array) and its result of the test data
	Vector<Vector <float[]>> testResults; // output of each network on each test example : testResult.get(digit).get(#network)[#example] 
	
	static public void initTestData(String testSetFileName)
	{
		Scanner scan = null;
		try {
			scan = new Scanner(new File(testSetFileName));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		testData = new ArrayList<VectorClassificationPair>();
		String line;
		int cls;
		while(scan.hasNext())
		{
			line = scan.nextLine();
			cls = Integer.parseInt(line.substring(0,1));
			String[] inputsStr = line.substring(2).split(",");
			float[] inputs = new float[inputsStr.length];
			for(int i =0 ; i < inputsStr.length ; i++){inputs[i] = Float.parseFloat(inputsStr[i]);}
			testData.add(new VectorClassificationPair(inputs, cls));
		}
		scan.close();
	}
	
	@SuppressWarnings("unchecked")
	public MlpEnsembleFitness()
	{
		try {
			FileInputStream readFile = new FileInputStream(RESULTS_FILE);
			ObjectInputStream fileStream = new ObjectInputStream(readFile);
			testResults = ((Vector<Vector<float[]>>) fileStream
					.readObject());
			fileStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		} 
		System.out.println("digits initialization for fitness completed.");
	}	
	
	@Override
	public double getFitness(Chromosome chromosome) {
		double success = 0;
		for(int exampleIndex = 0 ; exampleIndex < testData.size() ; exampleIndex++)
		{
			if(getClassification(exampleIndex, chromosome.getAllValues()) == testData.get(exampleIndex).getClassification())
			{
				success++;
			}	
		}
		return (success/testData.size())*100.0;
	}
	
	private int getClassificationOfOneBag(int testExamIndex, int[] mlps)
	{
		
		float[] array = {0,0,0,0,0,0,0,0,0,0};
		for(int digit = 0 ; digit < 10 ; ++digit)
		{
			array[digit] = testResults.get(digit).get(mlps[digit])[testExamIndex]; // get result of each network
		}			
		int max = 0;
		for(int i = 1; i < 10 ; ++i)
		{
			max = array[max]>=array[i] ? max : i;
		}
		return max;		
	}
	
	private int getClassification(int testExamIndex, List<Object> chromosomeMlps)
	{
		
		
		int[] array = {0,0,0,0,0,0,0,0,0,0};
		for(Object intArr : chromosomeMlps)
		{
			array[getClassificationOfOneBag(testExamIndex, (int[]) intArr)]++;
		}			
		int max = 0;
		for(int i = 1; i < 10 ; ++i)
		{
			max = array[max]>=array[i] ? max : i;
		}
		return max;		
	}

}
